package main

import (
	"bytes"
	"fmt"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"sync"
	"syscall"
	"time"
	"unsafe"

	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
)

/*
#cgo LDFLAGS: -lm
#include <stdio.h>
#include <stdlib.h>

int is_service_running_old(const char *service_name) {
    char command[256];
    snprintf(command, sizeof(command), "systemctl is-active --quiet %s", service_name);

    // 执行命令并检查返回值
    int result = system(command);

    // system() 返回值：0 表示服务正在运行，非零表示服务未运行
    return result == 0;
}

// 检查服务是否在运行
int is_service_running(const char *service_name) {
    char command[256];
    snprintf(command, sizeof(command), "ps -ef | grep -v grep | grep %s", service_name);

    // 执行命令，查看返回结果
    FILE *fp = popen(command, "r");
    if (fp == NULL) {
        perror("popen");
        return 0; // 错误，认为服务未运行
    }

    // 判断服务是否在运行
    char buffer[512];
    if (fgets(buffer, sizeof(buffer), fp) != NULL) {
        fclose(fp);
        return 1; // 服务正在运行
    } else {
        fclose(fp);
        return 0; // 服务未运行
    }
}

// 检查指定端口是否在监听
int is_port_listening(const int port) {
    char command[256];
    snprintf(command, sizeof(command), "netstat -tuln | grep :%d", port);

    printf("the command: %s", command);
    // 执行命令，查看返回结果
    FILE *fp = popen(command, "r");
    if (fp == NULL) {
        perror("popen");
        return 0; // 错误，认为端口未监听
    }

    // 如果有输出，说明端口正在监听
    char buffer[512];
    if (fgets(buffer, sizeof(buffer), fp) != NULL) {
        fclose(fp);
        return 1; // 端口在监听
    } else {
        fclose(fp);
        return 0; // 端口未监听
    }
}
*/
import "C"

func checkServiceStatusOld(serviceName string) bool {
	// 转换 Go 字符串为 C 字符串
	cServiceName := C.CString(serviceName)
	defer C.free(unsafe.Pointer(cServiceName))

	// 调用 C 函数
	return C.is_service_running(cServiceName) == 1
}

func checkServiceStatus(serviceName string) bool {
	// 转换 Go 字符串为 C 字符串
	cServiceName := C.CString(serviceName)
	// 检查服务是否运行
	res := C.is_service_running(cServiceName)
	if int(res) == 1 {
		fmt.Printf("Service %s is running.\n", serviceName)
	} else {
		fmt.Printf("Service %s is not running.\n", serviceName)
		return false
	}
	return true
}

func checkServicePortStatus(port int) (bool, error) {
	// 转换 Go 字符串为 C 字符串
	cPort := C.int(port)
	// 检查服务是否运行
	res := C.is_port_listening(cPort)
	if int(res) == 1 {
		fmt.Printf("Service port %d is running.\n", port)
		return true, nil
	} else {
		fmt.Printf("Service port %d is not running.\n", port)
		return false, fmt.Errorf("Service port %d is not running.\n", port)
	}
}

var SvrName string = "sqlsvr"
var SvrPort int = 21800
var SvrIp string = "192.168.31.135"
var NacosSvrIp string = "192.168.31.134"
var NacosSvrPort uint64 = 8848

func main() {
	// Nacos配置
	serverConfigs := []constant.ServerConfig{
		{
			IpAddr: NacosSvrIp,   // Nacos服务器地址
			Port:   NacosSvrPort, // Nacos服务器端口
		},
	}

	clientConfig := constant.ClientConfig{
		NamespaceId:         "default", // 如果使用了命名空间，请填写对应ID
		TimeoutMs:           5000,
		NotLoadCacheAtStart: true,
		LogDir:              "./nacos/log",
		CacheDir:            "./nacos/cache",
		LogLevel:            "debug",
	}

	// 创建配置客户端
	configClient, err := clients.NewConfigClient(vo.NacosClientParam{
		ClientConfig:  &clientConfig,
		ServerConfigs: serverConfigs,
	})
	if err != nil {
		log.Fatalf("创建Nacos配置客户端失败: %v\n", err)
	}

	// 创建服务注册客户端
	namingClient, err := clients.NewNamingClient(vo.NacosClientParam{
		ClientConfig:  &clientConfig,
		ServerConfigs: serverConfigs,
	})

	if err != nil {
		log.Fatalf("创建Nacos服务客户端失败: %v\n", err)
	}

	// 分布式锁相关
	lockKey := "sqlsvr-distributed-lock"
	lockValue := "lock-holder"
	leaseDuration := 5 * time.Second // 租约时间为5秒

	// 目标服务信息（需要下线的服务）
	targetServiceName := SvrName
	targetServiceIP := SvrIp
	targetServicePort := uint64(SvrPort)

	exitChan := make(chan os.Signal, 1)
	signal.Notify(exitChan, syscall.SIGINT, syscall.SIGTERM)

	// 检查服务状态
	// ok := checkServiceStatus("dmserver")
	ok := checkServiceStatus(SvrName)
	if ok {
		fmt.Printf("%s is running\n", SvrName)
	}

	ok, err = checkServicePortStatus(SvrPort)
	if ok && err == nil {
		fmt.Printf("port %d is running\n", SvrPort)
	}else {
		fmt.Println("checkServicePortStatusError:", err.Error())
		return
	}

	// 尝试获取锁
	stopChan := make(chan struct{})
	var wg sync.WaitGroup
	success := ttryAcquireLock(configClient, lockKey, lockValue, leaseDuration, stopChan, &wg)
	if success {
		fmt.Println("成功获取到分布式锁，启动续约机制。")
		defer rreleaseLock(configClient, lockKey, stopChan)
	} else {
		fmt.Println("准备强制下线目标服务...")
		err := forceDeregisterService(namingClient, targetServiceName, targetServiceIP, targetServicePort)
		if err != nil {
			log.Printf("强制下线服务失败: %v\n", err)
		} else {
			fmt.Println("目标服务已成功下线。")
		}
		return
	}

	// 模拟业务逻辑
	// 等待退出信号
	go func() {
		<-exitChan
		fmt.Println("\n接收到退出信号，开始清理操作...")
		rreleaseLock(configClient, lockKey, stopChan)
		wg.Wait() // 等待所有续约操作退出
		os.Exit(0)
	}()

	// 模拟业务逻辑
	fmt.Println("服务运行中...")
	select {}
}

// tryAcquireLock 尝试获取分布式锁并启动续约机制
func ttryAcquireLock(client config_client.IConfigClient, key, value string, leaseDuration time.Duration, stopChan chan struct{}, wg *sync.WaitGroup) bool {
	content := fmt.Sprintf("lock-value:%s", value)

	time.Sleep(3 * time.Second)
	// 校验是否成功持有锁
	_, err := client.GetConfig(vo.ConfigParam{
		DataId: key,
		Group:  "DEFAULT_GROUP",
	})
	if err != nil {
		log.Printf("检查锁状态失败: %v, 尝试获取锁\n", err)
		isGetLock := ggetLock(client, key, content)
		if isGetLock {
			log.Println("成功获取到锁\n", err)
			// 启动锁续约机制
			wg.Add(1)
			go sstartLeaseRenewal(client, key, value, leaseDuration, stopChan, wg)
			return true
		}
	}
	//if currentConfig != content {
	//	fmt.Printf("已经加锁，无法拿到")
	//	return false
	//}
	fmt.Printf("已经加锁，获取锁失败！\n")
	return false
}

// releaseLock 释放锁并停止续约
func rreleaseLock(client config_client.IConfigClient, key string, stopChan chan struct{}) {
	close(stopChan) // 停止续约

	success, err := client.DeleteConfig(vo.ConfigParam{
		DataId: key,
		Group:  "DEFAULT_GROUP",
	})
	if err != nil || !success {
		log.Printf("释放锁失败: %v\n", err)
	} else {
		fmt.Println("成功释放分布式锁。")
	}
}

// startLeaseRenewal 开启锁的续约机制
func sstartLeaseRenewal(client config_client.IConfigClient, key, value string, leaseDuration time.Duration, stopChan chan struct{}, wg *sync.WaitGroup) {
	defer wg.Done()
	ticker := time.NewTicker(leaseDuration / 2) // 每半个租约时间续约一次
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			content := fmt.Sprintf("lock-value:%s", value)
			success, err := client.PublishConfig(vo.ConfigParam{
				DataId:  key,
				Group:   "DEFAULT_GROUP",
				Content: content,
			})
			if err != nil || !success {
				log.Printf("续约锁失败: %v\n", err)
			} else {
				fmt.Println("锁续约成功。")
			}
		case <-stopChan:
			fmt.Println("停止锁续约。")
			return
		}
	}
}

func ggetLock(client config_client.IConfigClient, key, content string) bool {
	success, err := client.PublishConfig(vo.ConfigParam{
		DataId:  key,
		Group:   "DEFAULT_GROUP",
		Content: content,
	})
	if err != nil || !success {
		log.Printf("尝试获取锁失败: %v\n", err)
		return false
	}
	return true
}

// forceDeregisterService 强制下线指定服务实例
func forceDeregisterService(client naming_client.INamingClient, serviceName, ip string, port uint64) error {
	// --data-raw 'serviceName=go-demo-service&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip=192.168.31.134&port=8080&
	// ephemeral=true&weight=1&enabled=false&metadata=%7B%7D&namespaceId=default' \

	// 接口调用有BUG，使用curl调用
	//isOk, err := client.DeregisterInstance(vo.DeregisterInstanceParam{
	//	ServiceName: serviceName,
	//	Ip:          ip,
	//	Port:        port,
	//	Cluster:     "DEFAULT",
	//	GroupName:   "DEFAULT_GROUP",
	//	Ephemeral:   true, // 通常分布式服务实例是临时节点
	//})
	//if !isOk || err != nil {
	//	fmt.Errorf("强制下线服务实例失败: %w", err)
	//	panic("DeRegisterServiceInstance failed!" + err.Error())
	//}

	// 使用curl方式下线
	// curl 'http://192.168.31.134:8848/nacos/v1/ns/instance?' \
	//-X 'PUT' \
	//-H 'Accept: text/plain, */*; q=0.01' \
	//-H 'Accept-Language: zh-CN,zh;q=0.9' \
	//-H 'Authorization: {"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY1ODk5OTExOX0.Lktak5ePKsnP6yVetMTXbHWLm0wq0ZWBihR5RBOHtZk","tokenTtl":18000,"globalAdmin":true,"username":"nacos"}' \
	//-H 'Cache-Control: no-cache' \
	//-H 'Connection: keep-alive' \
	//-H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
	//-H 'Cookie: JSESSIONID=C3E2837FF1917C2E9286825756D72392' \
	//-H 'Origin: http://192.168.31.134:8848' \
	//-H 'Pragma: no-cache' \
	//-H 'Referer: http://192.168.31.134:8848/nacos/' \
	//-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
	//-H 'X-Requested-With: XMLHttpRequest' \
	//--data-raw 'serviceName=go-demo-service&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip=192.168.31.134&port=8080&ephemeral=true&weight=1&enabled=false&metadata=%7B%7D&namespaceId=default' \
	//--insecure

	// curl 'http://192.168.31.134:8848/nacos/v1/ns/instance?' -X 'PUT' --data-raw 'serviceName=go-demo-service&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip=192.168.31.134&port=8080&ephemeral=true&weight=1&enabled=false&metadata=%7B%7D&namespaceId=default' --insecure

	// 上线
	// curl 'http://192.168.31.134:8848/nacos/v1/ns/instance?' \
	//  -X 'PUT' \
	//  -H 'Accept: text/plain, */*; q=0.01' \
	//  -H 'Accept-Language: zh-CN,zh;q=0.9' \
	//  -H 'Authorization: {"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY1ODk5OTExOX0.Lktak5ePKsnP6yVetMTXbHWLm0wq0ZWBihR5RBOHtZk","tokenTtl":18000,"globalAdmin":true,"username":"nacos"}' \
	//  -H 'Cache-Control: no-cache' \
	//  -H 'Connection: keep-alive' \
	//  -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
	//  -H 'Cookie: JSESSIONID=C3E2837FF1917C2E9286825756D72392' \
	//  -H 'Origin: http://192.168.31.134:8848' \
	//  -H 'Pragma: no-cache' \
	//  -H 'Referer: http://192.168.31.134:8848/nacos/' \
	//  -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
	//  -H 'X-Requested-With: XMLHttpRequest' \
	//  --data-raw 'serviceName=go-demo-service&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip=192.168.31.134&port=8080&ephemeral=true&weight=1&enabled=true&metadata=%7B%7D&namespaceId=default' \
	//  --insecure

	// curl 'http://192.168.31.134:8848/nacos/v1/ns/instance?' -X 'PUT' --data-raw 'serviceName=go-demo-service&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip=192.168.31.134&port=8080&ephemeral=true&weight=1&enabled=true&metadata=%7B%7D&namespaceId=default' --insecure

	// commands := fmt.Sprintf("-XPUT http://%s:%d/nacos/v1/ns/instance? --data-raw serviceName=%s&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip=%s&port=%d&ephemeral=true&weight=1&enabled=false&namespaceId=default", NacosSvrIp, NacosSvrPort, SvrName,SvrIp, SvrPort)
	url := fmt.Sprintf("http://%s:%d/nacos/v1/ns/instance?", NacosSvrIp, NacosSvrPort)
	svrPortStr := strconv.Itoa(SvrPort)
	cmd := exec.Command("curl", "-XPUT",
		// "http://192.168.31.134:8848/nacos/v1/ns/instance?",
		url,
		"--data-raw",
		"serviceName="+SvrName+"&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip="+SvrIp+"&port="+svrPortStr+"&ephemeral=true&weight=1&enabled=false&metadata=%7B%7D&namespaceId=default",
		"--insecure")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		fmt.Println("命令执行出错:", err)
		return err
	}
	fmt.Printf("下线结果: %s\n", out.String())
	// fmt.Println(out.String())

	return nil
}

